package com.wyman.aop.framework.autoproxy;


import com.wyman.aop.*;
import com.wyman.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.wyman.aop.framework.ProxyFactory;
import com.wyman.aop.framework.adapter.MethodBeforeAdviceInterceptor;
import com.wyman.beans.BeanException;
import com.wyman.beans.PropertyValues;
import com.wyman.beans.factory.BeanFactory;
import com.wyman.beans.factory.BeanFactoryAware;
import com.wyman.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.wyman.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * @Author 李伟民
 * @Description
 * @DateTime 2024/12/29 00:21
 */
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    private DefaultListableBeanFactory beanFactory;

    //增加解决循环依赖的三级缓存处理逻辑 这里是为了解决重复创建代理对象的问题
    private final Set<Object> earlyProxyReferences = Collections.synchronizedSet(new HashSet<>());

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeanException {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }
    //  创造bean后 在初始化前 都会调用 beanClass就是有待代理的bean 判断该类适不适合切点对应的表达式
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeanException {
//        if (isInfrastructureClass(beanClass)) {
//            return null;
//        }
//        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
//        //advisor本质就是包装了切入点和切面
//        for (AspectJExpressionPointcutAdvisor advisor : advisors) {
//            ClassFilter classFilter = advisor.getPointcut().getClassFilter();
//            if (!classFilter.matches(beanClass)) {
//                continue;
//            }
//            AdvisedSupport advisedSupport = new AdvisedSupport();
//            TargetSource targetSource = null;
//            try {
//                //debug一个小时定位
//                targetSource =  new TargetSource(beanClass.getDeclaredConstructor().newInstance());
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//            advisedSupport.setTargetSource(targetSource);
//            //说明advice就是方法拦截器 什么时候设置了表达式？答：在xml文件定义中 设置了表达式值 此时beanDefinition中已经存放了advisor所以的信息
//            advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
//
//            advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
//            return new ProxyFactory(advisedSupport).getProxy();
//        }
//        return null;
        return  null;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeanException {
        return pvs;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) {
        return true;
    }

    public boolean isInfrastructureClass(Class<?> beanClass){
        //判断Advice是不是beanClass得接口或者父类
        return Advice.class.isAssignableFrom(beanClass)|| Pointcut.class.isAssignableFrom(beanClass)|| Advisor.class.isAssignableFrom(beanClass);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeanException {
        return bean;
    }

    protected Object wrapIfNecessary(Object bean,String beanName){
        if (isInfrastructureClass(bean.getClass())) {
            return bean;
        }
        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
        //advisor本质就是包装了切入点和切面
        for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            ClassFilter classFilter = advisor.getPointcut().getClassFilter();
            if (!classFilter.matches(bean.getClass())) {
                continue;
            }
            AdvisedSupport advisedSupport = new AdvisedSupport();
            TargetSource targetSource = null;
            try {
                //debug一个小时定位
                //16 这里target是全新的target 注入的信息丢失了 直接赋值为传入的bean 不能新建
                //targetSource =  new TargetSource(bean.getClass().getDeclaredConstructor().newInstance());
                targetSource =  new TargetSource(bean);


            } catch (Exception e) {
                e.printStackTrace();
            }

            advisedSupport.setTargetSource(targetSource);

            //说明advice就是方法拦截器 什么时候设置了表达式？答：在xml文件定义中 设置了表达式值 此时beanDefinition中已经存放了advisor所以的信息
            advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());

            advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
            //生成代理对象时 需要使用Cglib动态代理生成相应的代理对象
            advisedSupport.setProxyTargetClass(true);
            return new ProxyFactory(advisedSupport).getProxy();
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeanException {
        if(!earlyProxyReferences.contains(beanName)){
            return wrapIfNecessary(bean,beanName);
        }
        //如果已经包含了 说明传入的bean就是被代理过的bean 三级缓存的核心原因
        return bean;
    }

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) {
        earlyProxyReferences.add(beanName);
        return wrapIfNecessary(bean,beanName);
    }

}
